package weeny.pre.face.operation;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JSlider;

import prefuse.data.Tuple;
import prefuse.util.ColorLib;
import prefuse.visual.VisualItem;
import weeny.util.io.ModUtil;
import weeny.util.logs.Debug;

/**
 * Operation that supports:
 * 
 * 1) setting filtered items' colors to a certain alpha
 *    a) fill color
 *    b) stroke color
 *    c) text color
 * 2) right click to undo the previous setting
 * 
 * @author weeny
 *
 */
public class OpacityValueOperation extends AbstractOperation{
	protected JSlider slider = new JSlider(0, 255);
	protected String activeItem = null;
	protected Map<Tuple, Integer> originalValue = new HashMap();
	protected JPopupMenu popup = new JPopupMenu();{
		JMenuItem undo = new JMenuItem("undo");
		popup.add(undo);
		undo.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Iterator<Tuple> it = originalValue.keySet().iterator();
				String field = activeItem.trim();
				while (it.hasNext()){
					Tuple tp = it.next();
					if (tp.canGetInt(field)) {
						tp.setInt(field, originalValue.get(tp));
					}
				}
				operationBox.getVisualization().repaint();
			}
		});
	}
	protected MouseAdapter mouseListener = new MouseAdapter() {
		protected void updateNewAlphas(){
			int alpha = slider.getValue();
			Iterator<Tuple> it = originalValue.keySet().iterator();
			while (it.hasNext()){
				Tuple tp = it.next();
				if (tp.canGetInt(activeItem)) {
					int c = tp.getInt(activeItem);
					tp.setInt(activeItem, ColorLib.setAlpha(c, alpha));
				}
			}
			operationBox.updateInfo("Alpha is changed to "+alpha);
			operationBox.getVisualization().repaint();
		}
		@Override
		public void mousePressed(MouseEvent e) {
			if (e.getButton() == MouseEvent.BUTTON3) {
				popup.show(slider, e.getX(), e.getY());
				return;
			}
			//cache all the original colors
			originalValue.clear();
			boolean allowAll = ModUtil.isAltDown(e.getModifiers());
			Iterator<Tuple> it = operationBox.filteredItems(allowAll);
			while (it.hasNext()){
				Tuple tp = it.next();
				if (tp.canGetInt(activeItem)) {
					originalValue.put(tp, tp.getInt(activeItem));
				}
			}
		}
		@Override
		public void mouseReleased(MouseEvent e) {
			if (e.getButton() == MouseEvent.BUTTON3) {
				return;
			}
			updateNewAlphas();
		}
		@Override
		public void mouseDragged(MouseEvent e) {
			if (!slider.getValueIsAdjusting()) {
				return;
			}
			updateNewAlphas();
		}
	};
	
	public OpacityValueOperation(OperationBox operationBox) {
		super(operationBox);
		title = "Opacity Action";
		itemList.add(VisualItem.FILLCOLOR);
		itemList.add(VisualItem.STROKECOLOR);
		itemList.add(VisualItem.TEXTCOLOR);
		slider.setOrientation(JSlider.HORIZONTAL);
		slider.addMouseListener(mouseListener);
		slider.addMouseMotionListener(mouseListener);
		slider.setFocusable(false);
	}

	public void itemInvoked(String item, boolean isAltDown) {
		Debug.info("Item changed to: "+title+" -> "+item);
		activeItem = item;
		if (item.equals(title)) {
			slider.setEnabled(false);
		}
		else{
			slider.setEnabled(true);
		}
		operationBox.updateDetail(slider);
	}
}